<?php
/**
 * Created by PhpStorm.
 * User: dreamy
 * Date: 2021-06-04
 * Time: 11:16
 */
namespace common\services;

use common\models\TallyArap;
use common\models\TallyAttachment;
use common\models\TallyCategory;
use common\models\TallyRecord;
use Yii;
use yii\data\Pagination;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;

/**
 * 挂账 应收应付
 * Class TallyArapService
 *
 * @package common\services
 */
class TallyArapService extends BaseService{

    /**
     * 获取符合条件的所有记录 不带分页的
     * @param array $condition
     *
     * @return array
     */
    public static function getAll($condition=[])
    {
        $query = self::getQuery(null,$condition);
        $list  = $query
            ->orderBy('tally_time desc,id desc')
            ->limit(10000)
            ->asArray()
            ->all();
        return $list ?: [];
    }

    /**
     * 获取某个账本下的所有应收付记录
     * @param array $condition
     *
     * @return array|\yii\db\ActiveRecord[]
     * @desc
     */
    public static function getList($condition=[],$uid=null): array
    {
        $query = self::getQuery($uid,$condition);
        // 分页相关
        $count = $query->count();
        // 构造分页对象
        $pageSize = $_SERVER['PAGE_SIZE'] ?: 10 ;
        if(isset($condition['page_limie'])){
            $pageSize = $condition['page_limie'];
        }

        $pagination = new Pagination([
            'defaultPageSize' => $pageSize,
            'totalCount' => $count
        ]);
        $pagination->validatePage=false;
        $list  = $query
            ->orderBy('tally_time desc,id desc')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();
//        foreach($list as $k){
//            $list[$k]['amount_already']=$list[$k]['amount']-$list[$k]['amount_remain'];
//        }
//        $commandQuery = clone $query;
//        echo $commandQuery->createCommand()->getRawSql();
//        die;
        $list = $list ?: [];
        return [
            'data'       => $list,
            'pageInfo'   => [
                'totalCount' => intval($count) ,
                'pageSize'   => intval($pageSize)
            ]
        ];
    }

    /**
     * 获取某核销大项的所有账单明细
     * @param $arapId
     *
     * @return array|\yii\db\ActiveRecord[]
     */
    public static function getRecordList($arapId) {
        $list = TallyRecord::find()->where([
            'arap_id' => $arapId,
            'state' => TallyRecord::STATE_VALID
        ])->orderBy('tally_time desc')->all();
        return $list;
    }

    /**
     * 返回符合查询条件的query
     * 增加逻辑 账户的筛选 转入 与 转出账户 都要包含
     * @param       $uid
     * @param array $condition
     * @param bool $accountContain 是否包含账户相关的条件处理 | 统计的时候就需要自行组装账户条件
     *
     * @return \yii\db\ActiveQuery
     * @desc
     */
    public static function getQuery($uid=null,$condition=[],$accountContain=true)
    {
        $where = [];
        if($uid){
            $where = [
                'uid'   => $uid,
            ];
        }
        // 从DB获取
        $query = TallyArap::find()
            ->select('*')
            ->where($where);
        // 账本ID
        $tallyId = ArrayHelper::getValue($condition,'tally_id','');
        if($tallyId){
            $query->andFilterWhere(['=','tally_id',$tallyId]);
        }
        // 账目类别
        $type = ArrayHelper::getValue($condition,'type','');
        if($type){
            $query->andFilterWhere(['=','type',$type]);
        }
        // 上个id
        $last_id = ArrayHelper::getValue($condition,'last_id','');
        if($last_id){
            $query->andFilterWhere(['>','id',$last_id]);
        }

        // 分类ID
        $categoryId = ArrayHelper::getValue($condition,'category_id','');
        if($categoryId){
            $query->andFilterWhere(['=','category_id',$categoryId]);
        }
        // 分类ID集合
        $categoryIds = ArrayHelper::getValue($condition,'category_ids','');
        if($categoryIds){
            $query->andFilterWhere(['in','category_id',explode(',',$categoryIds)]);
        }
        $category_route_like = ArrayHelper::getValue($condition,'category_route_like','');

        if($category_route_like){
            $query->andFilterWhere(['like','category_route',','.$category_route_like.',']);
        }

        if($accountContain) {
            // 账户ID
            $accountId = ArrayHelper::getValue($condition,'account_id','');
            if($accountId){
//            $query->andFilterWhere(['=','account_id',$accountId]);
                $query->andFilterWhere(['or',
                        ['account_id' => $accountId],
                        ['account_dst_id' => $accountId],
                    ]
                );
            }
            // 账户ID集合
            $accountIds = ArrayHelper::getValue($condition,'account_ids','');
            if($accountIds){
//            $query->andFilterWhere(['in','account_id',explode(',',$accountIds)]);
                $query->andFilterWhere(['or',
                        ['in','account_id', explode(',',$accountIds) ],
                        ['in','account_dst_id',explode(',',$accountIds)],
                    ]
                );
            }
        }


        $stores = ArrayHelper::getValue($condition,'stores','');
        if($stores){
            $query->andFilterWhere(['in','store_id',$stores]);
        }

        $projects = ArrayHelper::getValue($condition,'projects','');
        if($projects){
            $query->andFilterWhere(['in','project_id',$projects]);
        }

        $members = ArrayHelper::getValue($condition,'members','');
        if($members){
            $query->andFilterWhere(['in','member_id',$members]);
        }

        $accounts = ArrayHelper::getValue($condition,'accounts','');
        if($accounts){
            $query->andFilterWhere(['or',
                    ['in','account_id', $accounts ],
                    ['in','account_dst_id',$accounts],
                ]
            );
        }
//        print_r($query->createCommand()->rawSql);
//        die;
        // 商家ID
        $storeId = ArrayHelper::getValue($condition,'store_id','');
        if($storeId){
            $query->andFilterWhere(['=','store_id',$storeId]);
        }
        // 商家ID集合
        $storeIds = ArrayHelper::getValue($condition,'store_ids','');
        if($storeIds){
            $query->andFilterWhere(['in','store_id',explode(',',$storeIds)]);
        }
        // 项目ID
        $projectId = ArrayHelper::getValue($condition,'project_id','');
        if($projectId){
            $query->andFilterWhere(['=','project_id',$projectId]);
        }
        // 项目ID集合
        $projectIds = ArrayHelper::getValue($condition,'project_ids','');
        if($projectIds){
            $query->andFilterWhere(['in','project_id',explode(',',$projectIds)]);
        }
        // 成员ID
        $memberId = ArrayHelper::getValue($condition,'member_id','');
        if($memberId){
            $query->andFilterWhere(['=','member_id',$memberId]);
        }
        // 成员ID集合
        $memberIds = ArrayHelper::getValue($condition,'member_ids','');
        if($memberIds){
            $query->andFilterWhere(['in','member_id',explode(',',$memberIds)]);
        }

        // 设置默认空 方便下面做判断
        if(!isset($condition['begin_date'])) $condition['begin_date'] = '';
        if(!isset($condition['end_date'])) $condition['end_date'] = '';

        // 时间段查询 包含右时间边界
        if($condition['begin_date'] != '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['between','tally_time',$condition['begin_date'], $condition['end_date']]);
        }
        if($condition['begin_date'] !='' && $condition['end_date'] == '') {
            $query->andFilterWhere(['>','tally_time',$condition['begin_date']]);
        }
        if($condition['begin_date'] == '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['<','tally_time',$condition['end_date']]);
        }

//        print_r($query->createCommand()->rawSql);
//        die;
        // 备注关键词
        $memo = ArrayHelper::getValue($condition,'memo','');
        if($memo){
            $query->andFilterWhere(['like','memo',$memo]);
        }
        // 包含状态
        $state = ArrayHelper::getValue($condition,'state');
        if($state !== null){
            $query->andFilterWhere(['=','state',$state]);
        }
        return $query;
    }

    /**
     * 添加一个总挂账记录
     * @param $formData
     * @return bool
     */
    public static function create($formData)
    {

        $model = new TallyArap();
        $model->load($formData,'');
        self::formatFieldBeforeSave($model);
        if ($model->validate() && $model->save()) {
            // 处理附件增加
            self::insertAttachment($formData,$model->id);
            return $model->id;
        }else{
            Yii::error('Tally arap insert error:'.current($model->getFirstErrors()).';post:'.Json::encode($formData,JSON_UNESCAPED_UNICODE));
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * @desc 数据更新之前的前置操作 一些冗余字段的处理
     * @param $model
     * @return mixed
     */
    public static function formatFieldBeforeSave(&$model)
    {
        // 整理挂账类别
        $model->category_name = TallyCategoryService::getTitleGlobal($model->category_id);
        $model->category_pid    = TallyCategoryService::getPidGlobal($model->category_id);
        $model->category_ppid    = TallyCategoryService::getPidGlobal($model->category_pid);
        $model->category_pname = TallyCategoryService::getTitleGlobal($model->category_pid);
        $model->category_ppname = TallyCategoryService::getTitleGlobal($model->category_ppid);
        $model->category_parent_id = $model->category_pid;
        if($model->category_ppname != ''){
            $model->category_parent_id = $model->category_ppid;
        }
        $model->category_child_id = $model->category_ppid == 0 ? $model->category_id : $model->category_pid;
        // 填充金额
        if(!$model->id) {
            $model->amount_remain = $model->amount;
        }
        $model->category_route = ','.$model->category_ppid.','.$model->category_pid.','.$model->category_id.',';



        // 获取账户名称
        $account_name = TallyAccountService::getTitleGlobal($model->account_id);
        if(is_null($account_name)) {
            self::setError('账户名称转换失败|请重新选择账户');
            return false ;
        }
        if($model->account_dst_id){
            $account_dst_name = TallyAccountService::getTitleGlobal($model->account_dst_id);
            $model->account_dst_name = $account_dst_name ;
        }
        $model->account_name = $account_name ;
        // 获取商家名称
        if($model->store_id) {
            $store_name = TallyStoreService::getTitleById($model->store_id);
            $model->store_name = $store_name ?: '';
        }else{
            $model->store_id = 0 ;
            $model->store_name = '' ;
        }
        // 获取项目情况
        if($model->project_id) {
            $project_name = TallyProjectService::getTitleById($model->project_id);
            $model->project_name = $project_name ?: '';
        }else{
            $model->project_id = 0 ;
            $model->project_name = '' ;
        }
        // 获取商户情况
        if($model->member_id) {
            $member_name = TallyMemberService::getTitleById($model->member_id);
            $model->member_name = $member_name ?: '';
        }else{
            $model->member_id = 0 ;
            $model->member_name = '' ;
        }
        return $model;
    }

    /**
     * @param $formData
     * @param $recId
     * @return bool
     * @notes 增加附件表
     */
    public static function insertAttachment($formData,$recId)
    {
        $attachS = explode(',', ArrayHelper::getValue($formData,'attachment',''));
        $attachS = array_filter($attachS);
        if(!empty($attachS)) {
            $data = [
                'tally_id'          => ArrayHelper::getValue($formData,'tally_id'),
                'tally_arap_id'   => $recId,
                'uid'               => ArrayHelper::getValue($formData,'uid'),
            ];
            foreach ($attachS as $attach) {
                if(!$attach) continue;
                $data['file_name'] = $attach;
                $model = new TallyAttachment();
                $model->load($data,'');
                $model->save();
            }
        }
        return true;
    }

    /**
     * @param $condition
     * @param $formData
     * @throws
     * @return bool
     */
    public static function update($condition,$formData)
    {
        $model = TallyArap::find()->where($condition)->one();
        if(!$model){
            self::setError('挂账记录不存在');
            return false ;
        }
        $oldModel = clone $model;
        $model->load($formData,'');
        $formData['tally_id'] = $model->tally_id;
        $model =  self::formatFieldBeforeSave($model);
        if(!$model) {
            return false; // 前置数据检查异常 返回错误
        }
        if ($model->validate() && $model->save()) {
            // 附件先全部清除掉
            self::deleteAttachment($formData,$model->id);
            // 处理附件增加
            self::insertAttachment($formData,$model->id);
            // 重新核对金额 更改结束状态
            self::calRelationAmount($model->id);
            return true ;
        }else{
            Yii::error('TallyArap update error:'.current($model->getFirstErrors()).';post:'.Json::encode($formData,JSON_UNESCAPED_UNICODE));
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * @notes 附件数据清理
     * @param $formData
     * @param $recId
     * @return bool
     */
    public static function deleteAttachment($formData,$recId)
    {
        $data = [
            'tally_id'          => ArrayHelper::getValue($formData,'tally_id'),
            'tally_arap_id'   => $recId,
//            'uid'               => ArrayHelper::getValue($formData,'uid'),
        ];
        TallyAttachment::deleteAll($data);
        return true;
    }

    /**
     * 根据arapID重新统计金额
     * @param $arapId
     *
     * @return bool
     */
    public static function calRelationAmount($arapId){
        $arapInfo = TallyArap::find()->where([
            'id' => $arapId
        ])->one();
        if(!$arapInfo) {
            self::setError('挂账记录不存在');
            return false;
        }
        $totalAmount = ToolService::moneyFormat($arapInfo->amount);
        // 统计已经核销的金额
        $alreadyAmount = TallyRecord::find()->where([
            'arap_id' => $arapId,
            'state' => TallyRecord::STATE_VALID
        ])->sum('amount');
        $alreadyAmount = $alreadyAmount ?: 0;
        // 计算剩余金额
        $remainAmount = ToolService::groupMathAdd([$totalAmount,-1*$alreadyAmount]);
        // 保存写入
        $arapInfo->amount_remain = $remainAmount;
        // 状态变更 只有正常状态的才进行重新核算1
        if(in_array($arapInfo->state,[
            TallyArap::STATE_VALID,
            TallyArap::STATE_ARAP_ING,
            TallyArap::STATE_ARAP_OVER
        ])) {
            if($totalAmount == $remainAmount ){
                $arapInfo->state = TallyArap::STATE_VALID;
            }else if($remainAmount > 0) {
                $arapInfo->state = TallyArap::STATE_ARAP_ING;
            }else if($remainAmount == 0) {
                $arapInfo->state = TallyArap::STATE_ARAP_OVER;
            }
        }
        $result = $arapInfo->save();
        return $result;
    }

    /**
     * @param $condition
     * @return bool
     * @throws
     */
    public static function delete($condition)
    {
        $arapId = $condition['id'];
        // 先检查应收应付大项下是否还存在账单记录
        $recCount = TallyRecord::find()->where([
            'arap_id' => $arapId,
            'state' => TallyRecord::STATE_VALID
        ])->count();
        if($recCount > 0 ) {
            self::setError('请先删除该挂账对应往来的明细账单');
            return false ;
        }
        $uid = ArrayHelper::getValue($condition,'uid');//操作者的UID
        unset($condition['uid']);
        $model = TallyArap::find()->where($condition)->one();
        if(!$model){
            self::setError('挂账记录不存在');
            return false ;
        }
        // 是否有权限进行删除操作
        if($model->uid == $uid){
            $canDel = true ; // 是本人创建的当然可以删除
        }else{
            // 该用户是否可删除账套下的账单 tallyId的角色关系
            $canDel =  TallyPmService::checkPermission($uid,$model->tally_id,'delete');
        }
        if(!$canDel){
            self::setError('不具备删除权限');
            return false ;
        }
        if ($model->delete()) {
            return true ;
        }else{
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * 统计某一时间段内的账户收支情况
     * 2021.1.15更新增加转账类型账单的收支统计
     * @param array $condition
     *
     * @return array
     * @desc
     */
    public static function countArap($condition=[],$uid=null): array
    {
        // $query = self::getQuery(null,$condition);
        $query =  TallyArap::find()->where([
            'tally_id' => $condition['tally_id']
        ]);
        if($uid != null){
            $query = $query->andFilterWhere(['=','uid',$uid]);
        }

        // 核销完毕状态下在应收金额
        $inOverMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_IN])
                    ->andFilterWhere(['=','state',TallyArap::STATE_ARAP_OVER])
                    ->sum('amount');
        // 核销完毕状态下在应付金额
        $outOverMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_OUT])
                    ->andFilterWhere(['=','state',TallyArap::STATE_ARAP_OVER])
                    ->sum('amount');
        // 全部状态下在应收金额
        $inAllMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_IN])
                    ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
                    ->sum('amount');
        // 全部状态下在应付金额
        $outAllMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_OUT])
                    ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
                    ->sum('amount');
        // 全部状态下在已收金额
        $inRemainMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_IN])
                    ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
                    ->sum('amount_remain');
        // 全部状态下在已付金额
        $outRemainMoney = (clone $query)
                    ->andFilterWhere(['=','type',TallyRecord::TYPE_OUT])
                    ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
                    ->sum('amount_remain');
        return [
            'inOver' => ToolService::moneyType($inOverMoney),
            'outOver' => ToolService::moneyType($outOverMoney),
            'inAll' => ToolService::moneyType($inAllMoney),
            'outAll' => ToolService::moneyType($outAllMoney),
            'inRemain' => ToolService::moneyType($inRemainMoney),
            'outRemain' => ToolService::moneyType($outRemainMoney),
            'inAlready' => ToolService::groupMathAdd([
                $inAllMoney, -1*$inRemainMoney
            ]),
            'outAlready' => ToolService::groupMathAdd([
                $outAllMoney,-1*$outRemainMoney
            ])
        ];
    }

    /**
     * 一段时间内的应收付统计，包括以下数据：
     * 1、该时间段新增加的应收付记录：应收额、应付额 通过查询arap表获得
     * 2、该时间段内核销的应收付记录：已收额、已付额 通过查询record表获得
     * @param array $condition
     * @return array
     * @throws
     */
    public static function countArapPeriod($condition=[],$uid = null)
    {
        // 区间内 应收付金额统计
        $query =  TallyArap::find()->where([
            'tally_id' => $condition['tally_id']
        ]);
        if($uid != null){
            $query = $query->andFilterWhere(['=','uid',$uid]);
        }
        // 设置默认空 方便下面做判断
        if(!isset($condition['begin_date'])) $condition['begin_date'] = '';
        if(!isset($condition['end_date'])) $condition['end_date'] = '';

        // 时间段查询 包含右时间边界
        if($condition['begin_date'] != '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['between','tally_time',$condition['begin_date'], $condition['end_date']]);
        }
        if($condition['begin_date'] != '' && $condition['end_date'] == '') {
            $query->andFilterWhere(['>','tally_time',$condition['begin_date']]);
        }
        if($condition['begin_date'] == '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['<','tally_time',$condition['end_date']]);
        }


        // 全部状态下的应收金额
        $inAllMoney = (clone $query)
            ->andFilterWhere(['=','type',TallyRecord::TYPE_IN])
            ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
            ->sum('amount');

        // 全部状态下的应付金额
        $outAllMoney = (clone $query)
            ->andFilterWhere(['=','type',TallyRecord::TYPE_OUT])
            ->andFilterWhere(['>','state',TallyArap::STATE_INVALID])
            ->sum('amount');

        // 统计区间内核销的应收付记录 表达为 已收 已付
        $query =  TallyRecord::find()->where([
            'tally_id' => $condition['tally_id']
        ]);
        if($uid != null){
            $query = $query->andFilterWhere(['=','uid',$uid]);
        }
        $query->andFilterWhere(['>','arap_id',0]); // 必须是核销相关条目
        $query->andFilterWhere(['=','state',TallyRecord::STATE_VALID]); // 必须是正常状态的账单
        // 时间段查询 包含右时间边界
        if($condition['begin_date'] != '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['between','tally_time',$condition['begin_date'], $condition['end_date']]);
        }
        if($condition['begin_date'] != '' && $condition['end_date'] == '') {
            $query->andFilterWhere(['>','tally_time',$condition['begin_date']]);
        }
        if($condition['begin_date'] == '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['<','tally_time',$condition['end_date']]);
        }
        // 已核销的应收部分
        $inOverMoney = (clone $query)
            ->andFilterWhere(['=','type',TallyRecord::TYPE_IN]) // 必须是收入账单
            ->sum('amount');
        // 已核销的应付部分
        $outOverMoney = (clone $query)
            ->andFilterWhere(['=','type',TallyRecord::TYPE_OUT]) // 必须是支出账单
            ->sum('amount');
        // 返回综合数据
        return [
            'inOver' => ToolService::moneyType($inOverMoney), // 区间内已收
            'outOver' => ToolService::moneyType($outOverMoney), // 区间内已付
            'inAll' => ToolService::moneyType($inAllMoney), // 区间内应收
            'outAll' => ToolService::moneyType($outAllMoney), // 区间内应付
        ];
    }
}
